import fetch from 'node-fetch';
import WebSocket from 'ws';
import path from 'path';
import fs from 'fs';

const storagePath = './temp/bilibili';

export class LiveRoomHeartbeatPlugin extends plugin {
  constructor() {
    super({
      name: '查bfangled',
      dsc: 'zy-yyds',
      event: 'message',
      priority: -Infinity,
      rule: [
        {
          reg: '^#?看直播(.*)$',
          fnc: 'cf'
        }
      ]
    });
  }

  async cf(e) {
    let roomid = e.msg.replace(/#?看直播/g, "").trim();
    logger.mark(`解析到的房间号为: ${roomid}`); // 记录重要标记信息

    if (!roomid || isNaN(roomid)) {
      e.reply("请输入有效的房间号", true);
      return;
    }

    const cookieFile = path.join(storagePath, 'user_cookies.json');
    let cookies = {};
    try {
      cookies = JSON.parse(fs.readFileSync(cookieFile, 'utf8'));
    } catch (err) {
      logger.error("无法读取cookie文件:", err);
      e.reply("未能绑定cookie，请发送b站扫码登录进行绑定", true);
      return;
    }

    const userCookies = cookies[e.user_id];
    if (!userCookies || !userCookies.SESSDATA) {
      e.reply("未能绑定cookie，请发送b站扫码登录进行绑定", true);
      return;
    }

    const {
      access_token, SESSDATA: sessdata, csrf, DedeUserID, DedeUserID__ckMd5, sid
    } = userCookies;

    const cookieStr = `access_token=${access_token}; SESSDATA=${sessdata}; csrf=${csrf}; DedeUserID=${DedeUserID}; DedeUserID__ckMd5=${DedeUserID__ckMd5}; sid=${sid}`;

    // 获取用户ID
    const urlInfo = 'https://api.bilibili.com/x/space/myinfo';
    const responseInfo = await fetch(urlInfo, {
      headers: {
        Cookie: cookieStr,
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
      }
    });
    const dataInfo = await responseInfo.json();
    const user = dataInfo.data;
    const uid = user && user.mid;

    if (!uid) {
      e.reply("获取用户ID失败，请检查网络或尝试重新绑定cookie", true);
      return;
    }

    // 初始化并启动WebSocket心跳和HTTP心跳，并设置4小时后关闭
    this.startHeartbeats(roomid, uid, cookieStr, e);

    // 设置4小时后停止HTTP心跳
    setTimeout(() => {
      logger.mark("4小时到了，准备停止HTTP心跳");
    }, 4 * 60 * 60 * 1000); // 4 hours in milliseconds
  }

  startHeartbeats(roomId, uid, cookies, e) {
    // WebSocket部分
    const wsManager = new WebSocketManager(roomId, uid, cookies, e);

    // HTTP心跳部分
    let heartbeatInterval = setInterval(() => this.httpHeartbeatThread(roomId, cookies), 60 * 1000); // 每分钟执行一次直播间心跳
    let globalHeartbeatInterval = setInterval(() => this.globalHeartbeat(cookies), 150 * 1000); // 每2.5分钟执行一次全局心跳

    // 设置4小时后关闭WebSocket连接和停止HTTP心跳
    const shutdownTimeout = setTimeout(() => {
      logger.mark("4小时到了，准备关闭所有心跳");

      if (wsManager.shutdownTimeout) clearTimeout(wsManager.shutdownTimeout);
      if (heartbeatInterval) clearInterval(heartbeatInterval);
      if (globalHeartbeatInterval) clearInterval(globalHeartbeatInterval);
      
      // 如果WebSocket仍然打开，则尝试关闭它
      if (wsManager.ws && wsManager.ws.readyState === WebSocket.OPEN) {
        wsManager.ws.close();
      }

      // 回复用户4小时已到，即将关闭直播间连接
      e.reply("4小时已到，即将关闭直播间连接", true);
    }, 4 * 60 * 60 * 1000); // 4 hours in milliseconds

    return shutdownTimeout;
  }

  httpHeartbeatThread(live_room_id, cookies) {
    const heartBeat = new BiliBiliHeartBeat(fetch, live_room_id, cookies);

    logger.info("发送直播间心跳...");
    heartBeat.xliveWebHeartBeat().then(response => {
      logger.info(`直播间心跳响应: ${JSON.stringify(response)}`);
    }).catch(error => logger.error("直播间心跳错误:", error));
  }

  globalHeartbeat(cookies) {
    const heartBeat = new BiliBiliHeartBeat(fetch, null, cookies);

    logger.info("发送全局心跳...");
    heartBeat.xliveHeartBeat().then(response => {
      logger.info(`全局心跳响应: ${JSON.stringify(response)}`);
    }).catch(error => logger.error("全局心跳错误:", error));
  }
}

class WebSocketManager {
  constructor(room_id, uid, cookies_str, e) {
    this.room_id = room_id;
    this.uid = uid;
    this.cookies_str = cookies_str;
    this.sequence = 1;
    this.connection_successful = false;
    this.e = e; // 保存e对象用于回复消息

    // 立即开始获取WebSocket信息
    this.getWsInfo(this.room_id).then(([wsUrl, token]) => {
      this.ws_url = wsUrl;
      this.token = token;

      // 使用setTimeout延迟初始化WebSocket连接
      setTimeout(() => {
        this.startWsThread();
      }, 25 * 1000); // 延迟25秒
    }).catch(error => {
      logger.error('初始化WebSocket连接时出错:', error);
    });
  }

  async getWsInfo(room_id) {
    const url = 'https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo';
    const headers = {
      Cookie: this.cookies_str,
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
      Accept: 'application/json, text/plain, */*',
      'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
      Referer: 'https://live.bilibili.com/',
      Origin: 'https://live.bilibili.com'
    };

    try {
      logger.mark(`正在请求WebSocket信息，房间号: ${room_id}`); // 记录重要标记信息
      const response = await fetch(`${url}?id=${room_id}`, { method: 'GET', headers });

      if (!response.ok) {
        logger.error(`获取WebSocket信息失败，状态码: ${response.status}`);
        throw new Error(`Failed to fetch WebSocket info: ${response.status}`);
      }

      const data = await response.json();
      if (data.code !== 0) {
        logger.error(`获取WebSocket信息失败，API返回错误: ${data.message || 'Unknown error'}`);
        throw new Error(data.message || 'Unknown error');
      }

      const hostList = data.data.host_list;
      if (!hostList.length) {
        logger.error("未找到可用的WebSocket服务器");
        throw new Error("No available WebSocket servers found.");
      }

      const wsHost = hostList[0];
      return [`ws://${wsHost.host}:${wsHost.ws_port}/sub`, data.data.token];
    } catch (error) {
      logger.error(`获取WebSocket信息时发生错误: ${error.message}`);
      throw error;
    }
  }

  buildPacket(data, operation) {
    const body = JSON.stringify(data);
    const packetLen = Buffer.byteLength(body) + 16;
    const header = Buffer.alloc(16);
    header.writeUInt32BE(packetLen, 0);
    header.writeUInt16BE(16, 4);
    header.writeUInt16BE(1, 6);
    header.writeUInt32BE(operation, 8);
    header.writeUInt32BE(this.sequence++, 12);
    return Buffer.concat([header, Buffer.from(body)]);
  }

  sendAuthPacket(ws) {
    const authData = {
      uid: parseInt(this.uid),
      roomid: parseInt(this.room_id),
      protover: 3,
      platform: "web",
      type: 2,
      key: this.token
    };
    const authPacket = this.buildPacket(authData, 7);
    ws.send(authPacket);
  }

  sendHeartbeat(ws) {
    const heartbeatPacket = this.buildPacket({}, 2);
    try {
      ws.send(heartbeatPacket);
      logger.mark(`UID ${this.uid} 发送了WebSocket心跳包，序列号: ${this.sequence - 1}`);
    } catch (e) {
      logger.error(`Error sending heartbeat: ${e.message}`);
    }
  }

  startWsThread() {
    const ws = new WebSocket(this.ws_url);

    ws.on('open', () => {
      this.sendAuthPacket(ws);

      // 使用setTimeout延迟首次心跳包的发送
      setTimeout(() => {
        this.sendHeartbeat(ws);
        // 设置定时器每30秒发送一次心跳包
        this.heartbeatInterval = setInterval(() => this.sendHeartbeat(ws), 30 * 1000);
        


        // 设置4小时后关闭WebSocket连接
        this.shutdownTimeout = setTimeout(() => {
          if (ws.readyState === WebSocket.OPEN) {
            logger.mark("4小时到了，准备关闭WebSocket连接");
            ws.close();

            // 回复用户4小时已到，即将关闭直播间连接
         //   this.e.reply("4小时已到，即将关闭直播间连接", true);
          }
        }, 4 * 60 * 60 * 1000); // 4 hours in milliseconds
      }, 25 * 1000); // 延迟25秒发送第一个心跳包
    });

    ws.on('message', (message) => {
      if (!this.connection_successful) {
        logger.mark("WebSocket连接成功"); // 记录重要标记信息
         this.e.reply("直播间连接成功", true);
        this.connection_successful = true;
      }
    });

    ws.on('error', (error) => {
      logger.error(`WebSocket error: ${error.message}`);
      ws.close();
    });

    ws.on('close', () => {
      logger.mark('WebSocket connection closed'); // 记录重要标记信息
      if (this.heartbeatInterval) {
        clearInterval(this.heartbeatInterval);
      }
      // 清除4小时后的关闭WebSocket连接的timeout
      if (this.shutdownTimeout) {
        clearTimeout(this.shutdownTimeout);
      }
    });

    this.ws = ws;
  }
}

class BiliBiliHeartBeat {
  constructor(session, biz_id, cookies) {
    this._session = session;
    this.biz_id = biz_id;
    this.cookies = cookies;
  }

  async xliveWebHeartBeat(last = 60, platform = "web") {
    const hb = Buffer.from(`${last}|${this.biz_id}|1|0`).toString('base64');
    const url = `https://live-trace.bilibili.com/xlive/rdata-interface/v1/heartbeat/webHeartBeat?hb=${hb}&pf=${platform}`;
    const headers = {
      Cookie: this.cookies,
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
      Accept: 'application/json, text/plain, */*',
      'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
      Referer: 'https://live.bilibili.com/',
      Origin: 'https://live.bilibili.com'
    };
    const response = await this._session(url, { method: 'GET', headers });
    return response.json();
  }

  async xliveHeartBeat() {
    const url = 'https://api.live.bilibili.com/relation/v1/Feed/heartBeat';
    const headers = {
      Cookie: this.cookies,
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
      Accept: 'application/json, text/plain, */*',
      'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
      Referer: 'https://live.bilibili.com/',
      Origin: 'https://live.bilibili.com'
    };
    const response = await this._session(url, { method: 'GET', headers });
    return response.json();
  }
}